﻿using System;
using System.Linq;
using System.Collections;
using System.Text.RegularExpressions;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Reflection;
using System.Data.Objects.DataClasses;

namespace ASPItalia.ModelVirtualCasting
{
    public static class Extensions
    {
        public static bool IsNull(this object obj)
        {
            return obj == null;
        }

        public static bool IsNotNull(this object obj)
        {
            return obj != null;
        }

        public static bool IsNullOrEmpty(this Array obj)
        {
            if (obj.IsNotNull())
                return obj.Length.Equals(0);
            return true;
        }

        public static bool IsNullOrEmpty(this IList obj)
        {
            if (obj.IsNotNull())
                return obj.Count.Equals(0);
            return true;
        }

        public static bool IsMatch(this string obj, string regexPattern, RegexOptions options)
        {
            if (string.IsNullOrEmpty(regexPattern))
                return false;
            return Regex.IsMatch(obj, regexPattern, options);
        }

        public static bool IsMatch(this string obj, string regexPattern)
        {
            return obj.IsMatch(regexPattern, RegexOptions.None);
        }

        public static string Truncate(this string obj, int maxLength)
        {
            if (!string.IsNullOrEmpty(obj) && obj.Length > 3 && maxLength > 3)
                return obj.Length > maxLength ? obj.Substring(0, maxLength - 3) + "..." : obj;
            return obj;
        }

        public static void ForEach<T>(this IEnumerable<T> source, Action<T> action)
        {
            for (var i = 0; i < source.Count(); i++)
                action(source.ElementAt(i));
        }

        public static IQueryable<TDTO> SelectDTO<T, TDTO>(this IQueryable<T> source)
        {
            return SelectDTO<T, TDTO>(source, true);
        }

        public static IQueryable<TDTO> SelectDTO<T, TDTO>(this IQueryable<T> source, bool onlyPrimitive)
        {
            ParameterExpression parameter = Expression.Parameter(typeof(T), "p");

            IEnumerable<MemberBinding> bindings = from p in DTOCopy<T, TDTO>.Properties
                                                  where (!onlyPrimitive) || p.PropertyType.IsPrimitive || p.PropertyType == typeof(String)
                                                  select (MemberBinding)Expression.Bind(p, Expression.Property(parameter, p.Name));

            Expression<Func<T, TDTO>> selector = Expression.Lambda<Func<T, TDTO>>(
                Expression.MemberInit(Expression.New(typeof(TDTO)),
                bindings),
                parameter);
            return source.Select(selector);
        }

        internal static class DTOCopy<TSource, TTarget>
        {

            private static Action<TSource, TTarget> copyAction;
            private static Action<TSource, TTarget> copyOnlyDifferentAction;
            private static IEnumerable<PropertyInfo> properties;

            static DTOCopy()
            {
                properties = typeof(TTarget).GetProperties(BindingFlags.Instance | BindingFlags.Public)
                    .Intersect(typeof(TSource).GetProperties(BindingFlags.Instance | BindingFlags.Public), new PropertyInfoComparare()).ToArray();

                if (typeof(TTarget).IsSubclassOf(typeof(EntityObject)))
                    properties = properties.Where(p =>
                    {
                        EdmScalarPropertyAttribute a = (EdmScalarPropertyAttribute)p.GetCustomAttributes(typeof(EdmScalarPropertyAttribute), false).FirstOrDefault();
                        return a == null || !a.EntityKeyProperty;
                    }).ToArray();
            }

            public static IEnumerable<PropertyInfo> Properties
            {
                get { return properties; }
            }

        }

		public static IEnumerable<T> OrderByRandom<T>(this IEnumerable<T> source)
		{
			System.Random random = new System.Random();
			return source.Select(x => new
			{
				Item = x,
				Random = random.NextDouble()
			}).OrderBy(x => x.Random).Select(x => x.Item);
		}


        #region PropertyInfoComparare

        internal class PropertyInfoComparare : IEqualityComparer<PropertyInfo>
        {
            #region IEqualityComparer<PropertyInfo> Members

            bool IEqualityComparer<PropertyInfo>.Equals(PropertyInfo x, PropertyInfo y)
            {
                return x.Name.Equals(y.Name);
            }

            int IEqualityComparer<PropertyInfo>.GetHashCode(PropertyInfo obj)
            {
                return obj.Name.GetHashCode();
            }

            #endregion
        }

        #endregion
		}
}
